import cProfile
from random import choice

from networkx import read_graphml
import pygame
from pygame import display, draw, event, Rect, Surface, time
from pygame.locals import *
from vizier import Viewer
from vizier.sprite import Sprite, update_paths
pygame.init()



#screen constants
SCREEN_SIZE = (400, 300)
SCREEN = display.set_mode(SCREEN_SIZE)



class ExampleSprite(Sprite):

    def __init__(self, image_key, pos, node):
        Sprite.__init__(self, image_key, pos, node)
        self.movement = (1, -1)

    def update(self):
        self.rect.move_ip(*self.movement)

    def handle_collisions(self, walls):
        rect = self.rect
        for wall in walls:
            if rect.colliderect(wall.rect):
                movement = self.movement
                rect.move_ip(-movement[0], -movement[1])
                self.movement = (-movement[1], movement[0])



def main():
    #graph = read_graphml('./resources/graph/example.graphml')
    graph = read_graphml('./resources/graph/wrap.graphml')
    #graph = read_graphml('./resources/graph/example.graphml')
    frustum_size = (400, 300)
    viewer_rect = Rect((0, 0), (400, 300))
    viewer = Viewer(
        frustum_size, (125, 125), '4', graph, viewer_rect, zoom_out_limit=1)

    sprite_key = ['.', 'resources', 'img', 'sprite.tga']
    vertwall_key = ['.', 'resources', 'img', 'vertwall.tga']
    horiwall_key = ['.', 'resources', 'img', 'horiwall.tga']
    keys = update_paths(sprite_key, vertwall_key, horiwall_key)
    sprite_key, vertwall_key, horiwall_key = keys

    leftwall0 = Sprite(vertwall_key, (0, 0), '0')
    leftwall3 = Sprite(vertwall_key, (0, 0), '3')
    leftwall6 = Sprite(vertwall_key, (0, 0), '6')
    rightwall2 = Sprite(vertwall_key, (265, 0), '2')
    rightwall5 = Sprite(vertwall_key, (265, 0), '5')
    rightwall8 = Sprite(vertwall_key, (265, 0), '8')
    topwall0 = Sprite(horiwall_key, (0, 0), '0')
    topwall1 = Sprite(horiwall_key, (0, 0), '1')
    topwall2 = Sprite(horiwall_key, (0, 0), '2')
    botwall6 = Sprite(horiwall_key, (0, 265), '6')
    botwall7 = Sprite(horiwall_key, (0, 265), '7')
    botwall8 = Sprite(horiwall_key, (0, 265), '8')
    walls = [leftwall0, leftwall3, leftwall6,
             rightwall2, rightwall5, rightwall8,
             topwall0, topwall1, topwall2,
             botwall6, botwall7, botwall8]
    sprite = ExampleSprite(sprite_key, (0, 0), '4')
    viewer.group_evict.add(sprite, *walls)
    viewer.scroll(0, 0) # sort sprites

    clock = time.Clock()
    SCROLL_UP = False
    SCROLL_DOWN = False
    SCROLL_LEFT = False
    SCROLL_RIGHT = False
    ZOOM_IN = False
    ZOOM_OUT = False
    while 1:
        clock.tick(40)
        for ev in event.get():
            if ev.type == KEYDOWN:
                if ev.key == K_UP: SCROLL_UP = True
                if ev.key == K_DOWN: SCROLL_DOWN = True
                if ev.key == K_LEFT: SCROLL_LEFT = True
                if ev.key == K_RIGHT: SCROLL_RIGHT = True
                if ev.key == K_PAGEDOWN: ZOOM_IN = True
                if ev.key == K_PAGEUP: ZOOM_OUT = True
                if ev.key == K_q: exit()
            if ev.type == KEYUP:
                if ev.key == K_UP: SCROLL_UP = False
                if ev.key == K_DOWN: SCROLL_DOWN = False
                if ev.key == K_LEFT: SCROLL_LEFT = False
                if ev.key == K_RIGHT: SCROLL_RIGHT = False
                if ev.key == K_PAGEDOWN: ZOOM_IN = False
                if ev.key == K_PAGEUP: ZOOM_OUT = False
            if ev.type == MOUSEBUTTONDOWN:
                print viewer.get_mouse(ev.pos)
        if SCROLL_UP: viewer.scroll(0, -5)
        if SCROLL_DOWN: viewer.scroll(0, 5)
        if SCROLL_LEFT: viewer.scroll(-5, 0)
        if SCROLL_RIGHT: viewer.scroll(5, 0)
        if ZOOM_IN: viewer.zoom(0.02)
        if ZOOM_OUT: viewer.zoom(-0.02)
        if sprite in viewer.group_active: sprite.rotate(angle_delta=5)
        viewer.update0()
        sprite.update()
        if sprite in viewer.group_active:
            _walls = [wall for wall in walls if wall in viewer.group_active]
            sprite.handle_collisions(_walls)
        viewer.update1()
        viewer.draw()
        SCREEN.blit(viewer.surf, viewer.rect)#, area=viewer.area)
        draw.circle(SCREEN, (255, 0, 255), viewer_rect.center, 5)
        display.flip()



if __name__ == '__main__':
    print """
    welcome to the vizier example!

    the checkerboards are nodes, you can determine where two nodes meet by the
      meeting of the checkerboard patterns.  the red squares were placed
      randomly to break the monotony and provide points of reference.  the nodes
      are arranged in the following pattern:

      0 1 2
      3 4 5
      6 7 8

    the magenta dot is the center of the frustum
    the green square is a sprite
    the blue border around the outer edges of the outer nodes is a wall to
      prevent the sprite from exiting the nodes.

    if you scroll the center of the frustum, indicated by the magenta dot, off
      edges of the nodes, indicated by the blue walls, vizier will raise an
      error.  if you move the frustum center off the nodes, then the frustum is
      literally 'no where'; obviously not a good condition.  typically, client
      code will provide limitations to frustum movement to prevent the frustum
      from leaving the nodes.  indeed, client code should prevent even the
      frustum edge from scrolling over the outermost node edges, as will be
      discussed in the next paragraph.  the example allows the frustum to leave
      the nodes as, well, an example.

    when you scroll the edge of the viewer beyond the edge of the nodes,
      indicated by the blue wall, vizier does not clear the old surface, and it
      creates the familiar uncleared-repeating pattern.  client code should
      prevent the frustum edges from scrolling over node edges.  typically, game
      objects such as walls, trees, mountains, rivers, or what have you should
      prevent the player from approaching the outermost node edges.

    things to do-
      verify that the sprite is moved to the inactive group.  wait for it to
        enter a corner node, such as node 0, 2, 6, or 8, then move to the
        opposite corner.  wait a bit.  you will never see the sprite again as
        long as you wait.  move back to the corner were the sprite was and it
        will still be there.  it will start moving the moment it becomes visible
        again.  this demonstrates that both nodes and the sprites on them are
        evicted when they leave the frustum

      click on the screen.  the script will print the mouse's position in node
        space; the position on the frustum node and the node id.  scroll around
        and verify that the image is composed of different nodes, each with
        their own node space, by clicking on them and observing the mouse
        position in node space and the node id.

      scroll over the outer edges of the outermost nodes.  an error will be
        thrown.  the error will provide your world position at the time you
        left the nodes, and will state that this position does not map to any
        node.

    enjoy vizier.  it is a working package, and the interfaces should not
      change, but it is still in development and improvements may be made.
      future releases will experiment with using multithreading to put the disk
      access in its own thread.
    """
    cProfile.run('main()')
